package com.das.mechanic_base.app;

import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.webkit.WebView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.alibaba.android.arouter.launcher.ARouter;
import com.bytedance.boost_multidex.BoostMultiDex;
import com.danikula.videocache.HttpProxyCacheServer;
import com.das.mechanic_base.BuildConfig;
import com.das.mechanic_base.R;
import com.das.mechanic_base.bean.app.BrandMechanicBean;
import com.das.mechanic_base.bean.open.OpenTokenBean;
import com.das.mechanic_base.gen.DaoMaster;
import com.das.mechanic_base.gen.DaoSession;
import com.das.mechanic_base.mapi.api.NetWorkHttp;
import com.das.mechanic_base.mapi.response.HttpCallBack;
import com.das.mechanic_base.mapi.schedulers.RxSchedulersHelper;
import com.das.mechanic_base.utils.LanguageResources;
import com.das.mechanic_base.utils.LanguageUtiles;
import com.das.mechanic_base.utils.MethodTransferHelper;
import com.das.mechanic_base.utils.SpHelper;
import com.das.mechanic_base.utils.WebViewPool;
import com.das.mechanic_base.utils.X3SoundPlayUtils;
import com.das.mechanic_base.utils.X3StringUtils;
import com.das.mechanic_base.utils.X3ToastUtils;
import com.downloader.PRDownloader;
import com.google.gson.Gson;
import com.hjq.permissions.XXPermissions;
import com.hjq.toast.ToastUtils;
import com.iflytek.cloud.Setting;
import com.iflytek.cloud.SpeechConstant;
import com.iflytek.cloud.SpeechUtility;
import com.tencent.bugly.crashreport.CrashReport;
import com.tencent.mmkv.MMKV;
import com.umeng.analytics.MobclickAgent;
import com.umeng.commonsdk.UMConfigure;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.disposables.Disposable;
import io.reactivex.plugins.RxJavaPlugins;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by chensi on 2018/3/6.
 */
public class X3MyApp implements IComponentApplication, Application.ActivityLifecycleCallbacks {

    private String TAG = "MyApp";

    protected static Application mApp;

    public static String Xpush_Suffix = "";

    private String Xpush_Server = "";

    public static List<Activity> mActivities = new ArrayList<>();

    public static Map<String, Object> strMap;

    private static HttpProxyCacheServer proxy;

    private DaoMaster.DevOpenHelper mHelper;
    private SQLiteDatabase db;
    private DaoMaster mDaoMaster;
    private DaoSession mDaoSession;

    public IAloneEventCallback iAloneEventCallback;

    public IAloneCreateServiceCallback iAloneCreateServiceCallback;

    private static X3MyApp instance;

    private IMyAppNoticeOther iMyAppNoticeOther;
    private String accessKey;
    private String openUrl;

    private X3MyApp() {

    }

    /**
     * 获取单例
     *
     * @return
     */
    public static X3MyApp getInstance() {
        if (instance == null) {
            instance = new X3MyApp();
        }
        return instance;
    }

    @Override
    public void init(Application application) {
        mApp = application;
        mApp.registerActivityLifecycleCallbacks(this);
//        MMKV.initialize(mApp, libName -> ReLinker.loadLibrary(mApp, libName));
        MMKV.initialize(mApp);

        X3StringUtils.downAppStringFile(mApp);

        ARouter.openDebug();
        ARouter.openLog();
        ARouter.init(mApp);

        X3SoundPlayUtils.init(mApp);

        PRDownloader.initialize(mApp);

        //友盟统计
        UMConfigure.init(mApp, com.das.mechanic_base.BuildConfig.UM_APPKEY, "Umeng", UMConfigure.DEVICE_TYPE_PHONE, "");
        MobclickAgent.setPageCollectionMode(MobclickAgent.PageMode.LEGACY_MANUAL);

        // 初始化bugly
        CrashReport.initCrashReport(mApp,BuildConfig.DEBUG ? "fcdcc224ce" : "e8b6338743", BuildConfig.DEBUG);

        if (!BuildConfig.DEBUG) {
            initError();
        }

        // 语音听写功能 关闭定位请求
        Setting.setLocationEnable(false);
        SpeechUtility.createUtility(mApp, SpeechConstant.APPID + "=" + BuildConfig.Speech_AppKey);

        ToastUtils.init(mApp);
        setDatabase();

        try {
            initPieWebView();
            WebViewPool.init(mApp);
        }catch (Exception e) {
        }
        requestBrandConfig();

        //上传存储的方法调用
        MethodTransferHelper.getInstance().upLoad();
    }

    private void initError() {
        // 捕获多次异常
        RxJavaPlugins.setErrorHandler(throwable -> Log.e("RxJavaPlugins","unknown exception=" + throwable.toString()));

        new Handler(Looper.getMainLooper()).post(() -> {
            //主线程异常拦截
            while (true) {
                try {
                    Looper.loop();//主线程的异常会从这里抛出
                } catch (Throwable e) {
                    CrashReport.postCatchedException(e);
                    Log.e("SSSS","主线程异常:" + e.toString());
                }
            }
        });
//        所有线程异常拦截，由于主线程的异常都被我们catch住了，所以下面的代码拦截到的都是子线程的异常
        Thread.setDefaultUncaughtExceptionHandler((t, e) -> CrashReport.postCatchedException(e));
    }

    private void requestBrandConfig() {
        String token = (String) SpHelper.getData("token", "");
        if (X3StringUtils.isEmpty(token)) {
            return;
        }
        NetWorkHttp.getApi().getBrandMechConfig()
                .compose(RxSchedulersHelper.defaultComposeRequest())
                .subscribe(new HttpCallBack<BrandMechanicBean>() {
                    @Override
                    protected void onDone(BrandMechanicBean mechanicBean) {
                        if (mechanicBean == null) {
                            return;
                        }
                        SpHelper.saveData(X3Constent.BRAND_MECHANIC_CONFIG,mechanicBean.toString());

                    }

                    @Override
                    protected void showError(String error) {

                    }
                });

    }



    private void initPieWebView() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            String processName = mApp.getProcessName();
            if (!mApp.getPackageName().equals(processName)) {//判断是否是默认进程名称
                WebView.setDataDirectorySuffix(processName);
            }
        }
    }

    public X3MyApp setiMyAppNoticeOther(IMyAppNoticeOther iMyAppNoticeOther) {
        this.iMyAppNoticeOther = iMyAppNoticeOther;
        return this;
    }

    @Override
    public void attachContext(Context base) {
        BoostMultiDex.install(base);
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        LanguageUtiles.changeAppLanguage(LanguageUtiles.getAppLocale(getTopActivity()).locale,true,getTopActivity());
        LanguageUtiles.setApplicationLanguage(LanguageUtiles.appContext);
        LanguageUtiles.setApplicationLanguage(mApp);
    }

    public void logout() {
        if (iMyAppNoticeOther != null) {
            iMyAppNoticeOther.logout();
        }
        ARouter.getInstance().build(X3AppRouterConstants.Router.LOGIN_CONTAINER)
                .withTransition(R.anim.slide_in_right, R.anim.slide_out_left)
                .withFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK)
                .navigation();
        X3MyApp.getInstance().clearActivities();
    }

    /**
     * sdk 使用同步token
     * @param
     */
    public void loginSync(String accessKey,String openUrl) {
        this.accessKey = accessKey;
        this.openUrl = openUrl;
        SpHelper.saveData(X3Constent.IS_OPEN_SDK,true);
        syncAppToken(accessKey, openUrl);
    }

    public void loginSync() {
        SpHelper.saveData(X3Constent.IS_OPEN_SDK,true);
        syncAppToken(accessKey, openUrl);
    }

    /**
     * 通过openapi获取token
     * @param accessKey
     */
    private void syncAppToken(String accessKey,String openUrl) {
        Observable.create((ObservableOnSubscribe<String>) e -> {
            OkHttpClient client = new OkHttpClient();
            RequestBody body = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), "{'method':'autox3.system.app.token.get'}");

            Request request = new Request.Builder()
                    .url(openUrl + "/openapi/api-v1/rest")
                    .addHeader("Authorization",accessKey)
                    .post(body)
                    .build();
            Response execute = client.newCall(request).execute();
            String string = execute.body().string();
            e.onNext(string);

        }).map(address -> address)
                .compose(RxSchedulersHelper.defaultComposeRequest())
                .subscribe(new Observer<String>() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }

                    @Override
                    public void onNext(String locationBean) {
                        Gson gson = new Gson();

                        OpenTokenBean tokenBean = gson.fromJson(locationBean,OpenTokenBean.class);
                        long status = tokenBean.status;
                        if (status != 0) {
                            return;
                        }
                        OpenTokenBean.DataBean data = tokenBean.data;

                        if (data == null) {
                            return;
                        }
                        X3Constent.saveBaseUrl(data.localUrl + X3Constent.BASE_URL_ADDRESS,data.h5LocalUrl + X3Constent.BASE_SERVICE_URL_ADDRESS);
                        SpHelper.saveData("token",data.localToken);
                        requestBrandConfig();
                    }

                    @Override
                    public void onError(Throwable e) {

                    }

                    @Override
                    public void onComplete() {

                    }
                });
    }

    public Application getApp() {
        return mApp;
    }

    public Activity getTopActivity() {
        if (mActivities.size() > 0) {
            return mActivities.get(mActivities.size() - 1);
        } else {
            return null;
        }
    }

    public void addActivity(Activity activity) {
        mActivities.add(activity);
    }

    public void removeActivity(Activity activity) {
        mActivities.remove(activity);
    }

    public void clearActivities() {
        for (Activity activity : mActivities) {
            if (activity != null) {
                activity.finish();
            }
        }
        mActivities.clear();
    }

    public HttpProxyCacheServer getVideoCacheProxy(Context context) {
        return proxy == null ? (proxy = newProxy()) : proxy;
    }

    private HttpProxyCacheServer newProxy() {
        return new HttpProxyCacheServer(mApp);
    }

    @Override
    public void getResources(Resources resources) {
        if (resources == null) {
            resources = new LanguageResources(resources);
        }
        Configuration config = new Configuration();
        config.setToDefaults();
        resources.updateConfiguration(config,resources.getDisplayMetrics());
    }

    @Override
    public void setXpush_Suffix(String xpush_Suffix, String Xpush_Server) {
        this.Xpush_Suffix = xpush_Suffix;
        this.Xpush_Server = Xpush_Server;
    }

    private void setDatabase() {
        mHelper = new DaoMaster.DevOpenHelper(mApp, "notes-db", null);
        db = mHelper.getWritableDatabase();
        mDaoMaster = new DaoMaster(db);
        mDaoSession = mDaoMaster.newSession();
    }

    public DaoSession getDaoSession() {
        return mDaoSession;
    }

    private SQLiteDatabase getDb() {
        return db;
    }

    /**
     * 在Activity获取 manifestPlaceholders 的值
     * <p>
     * 注意:在AndroidManifest.xml 该Activity标签下加上  <meta-data  android:name="label111" android:value="${label}" /><!--这一句起到至关重要作用-->
     *
     * @param context
     * @param key
     * @return
     */
    public String getActivityPlaceholders(Context context, String key) {

        String placeholdersValues = "";
        try {
            ApplicationInfo appInfo = mApp.getPackageManager().getApplicationInfo(mApp.getPackageName(), PackageManager.GET_META_DATA);//Activity中
            if (appInfo == null) {
                return "";
            }
            Bundle metaData = appInfo.metaData;
            if (metaData == null) {
                return "";
            }
            placeholdersValues = metaData.getString(key);
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        }
        return placeholdersValues;
    }

    @Override
    public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {
        if (iMyAppNoticeOther != null) {
            iMyAppNoticeOther.addImListener(activity.getLocalClassName());
        }
    }

    @Override
    public void onActivityStarted(@NonNull Activity activity) {

    }

    @Override
    public void onActivityResumed(@NonNull Activity activity) {

    }

    @Override
    public void onActivityPaused(@NonNull Activity activity) {

    }

    @Override
    public void onActivityStopped(@NonNull Activity activity) {

    }

    @Override
    public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {

    }

    @Override
    public void onActivityDestroyed(@NonNull Activity activity) {
        if (iMyAppNoticeOther != null) {
            iMyAppNoticeOther.removeImListener(activity.getLocalClassName());
        }
    }

    /**
     * 跳转到检测单
     * @param workBaseId
     * @param receiveId
     */
    public void startAlone(long workBaseId,long receiveId,IAloneEventCallback iAloneEventCallback) {
        this.iAloneEventCallback = iAloneEventCallback;
        Bundle bundle = new Bundle();
        bundle.putLong("id",workBaseId);
        bundle.putLong("receiveBaseId",receiveId);
        X3RouterCenter.startNavigate(X3AppRouterConstants.Router.MAIN_TAIN,bundle);
    }

    /**
     * 跳转到施工单
     * @param workBaseId
     * @param receiveId
     */
    public void startWork(long workBaseId,long receiveId,IAloneEventCallback iAloneEventCallback) {
        this.iAloneEventCallback = iAloneEventCallback;
        Bundle bundle = new Bundle();
        bundle.putLong("id",workBaseId);
        bundle.putLong("receiveBaseId",receiveId);
        X3RouterCenter.startNavigate(X3AppRouterConstants.Router.MAIN_SIVE,bundle);
    }

    /**
     * 跳转到接车单列表
     */
    public void startServiceOrderList(IAloneEventCallback iAloneEventCallback) {
        this.iAloneEventCallback = iAloneEventCallback;
        Bundle bundle = new Bundle();
        X3RouterCenter.startNavigate(X3AppRouterConstants.Router.SERVICE_LIST,bundle);
    }

    /**
     * 创建接车单
     * @param iAloneEventCallback
     */
    public void startCreateServiceOrder(IAloneEventCallback iAloneEventCallback) {
        this.iAloneEventCallback = iAloneEventCallback;
        X3RouterCenter.startNavigate(X3AppRouterConstants.Router.CREATE_SERVICE,null);
    }

    /**
     * 跳转到报告页
     * @param reportUrl
     */
    public void startVehicleReport(String reportUrl) {
        Bundle bundle = new Bundle();
        bundle.putBoolean("isDark",true);
        bundle.putString("webUrl", reportUrl);
        X3RouterCenter.startNavigate(X3AppRouterConstants.Router.GROUND_PUSH,bundle);
    }
}
